use std::io::BufRead;

use serde::de;

use crate::de::Deserializer;
use crate::events::Event;
use crate::DeError;

/// A SeqAccess
pub struct SeqAccess<'a, R: BufRead> {
    de: &'a mut Deserializer<R>,
    max_size: Option<usize>,
}

impl<'a, R: BufRead> SeqAccess<'a, R> {
    /// Get a new SeqAccess
    pub fn new(de: &'a mut Deserializer<R>, max_size: Option<usize>) -> Result<Self, DeError> {
        Ok(SeqAccess { de, max_size })
    }
}

impl<'de, 'a, R: 'a + BufRead> de::SeqAccess<'de> for SeqAccess<'a, R> {
    type Error = DeError;

    fn next_element_seed<T: de::DeserializeSeed<'de>>(
        &mut self,
        seed: T,
    ) -> Result<Option<T::Value>, DeError> {
        if let Some(s) = self.max_size.as_mut() {
            if *s == 0 {
                return Ok(None);
            }
            *s -= 1;
        }

        if let Some(Event::Start(e)) = self.de.peek()? {
            match &*String::from_utf8_lossy(e.name()) {
                "data" | "struct" => {
                    let res = seed.deserialize(&mut *self.de).map(Some);
                    return res;
                }
                unknown => {
                    let unknown = String::from(unknown);
                    println!("Unknown tag found in seq: {}", unknown);
                    self.de.read_to_end(unknown.as_ref())?;
                }
            }
        }
        Ok(None)
    }

    fn size_hint(&self) -> Option<usize> {
        self.max_size
    }
}
